#include "StdAfx.h"
#include ".\fileoperation.h"

const HANDLE CFile::hFileNull = INVALID_HANDLE_VALUE;

CFile::CFile()
{
	m_hFile = INVALID_HANDLE_VALUE;
	m_bCloseOnDelete = FALSE;
}

CFile::CFile(HANDLE hFile)
{
	m_hFile = hFile;
	m_bCloseOnDelete = FALSE;
}

CFile::CFile(LPCTSTR lpszFileName, UINT nOpenFlags)
{
	m_hFile = INVALID_HANDLE_VALUE;
	
	if (!Open(lpszFileName, nOpenFlags))
	{
	
	}
//	AfxThrowFileException(e.m_cause, e.m_lOsError, e.m_strFileName);
}

CFile::~CFile()
{
	if (m_hFile != INVALID_HANDLE_VALUE && m_bCloseOnDelete)
		Close();
}


BOOL CFile::Open(LPCTSTR lpszFileName, UINT nOpenFlags )
{
	// shouldn't open an already open file (it will leak)
	ASSERT(m_hFile == INVALID_HANDLE_VALUE);

	// CFile objects are always binary and CreateFile does not need flag
	nOpenFlags &= ~(UINT)typeBinary;

	m_bCloseOnDelete = FALSE;

	m_hFile = INVALID_HANDLE_VALUE;
	m_strFileName.Empty();
		
	m_strFileName = lpszFileName;

//	ASSERT(sizeof(HANDLE) == sizeof(UINT));
	ASSERT(shareCompat == 0);

	// map read/write mode
	ASSERT((modeRead|modeWrite|modeReadWrite) == 3);
	DWORD dwAccess = 0;
	switch (nOpenFlags & 3)
	{
	case modeRead:
		dwAccess = GENERIC_READ;
		break;
	case modeWrite:
		dwAccess = GENERIC_WRITE;
		break;
	case modeReadWrite:
		dwAccess = GENERIC_READ | GENERIC_WRITE;
		break;
	default:
		ASSERT(FALSE);  // invalid share mode
	}

	// map share mode
	DWORD dwShareMode = 0;
	switch (nOpenFlags & 0x70)    // map compatibility mode to exclusive
	{
	default:
		ASSERT(FALSE);  // invalid share mode?
	case shareCompat:
	case shareExclusive:
		dwShareMode = 0;
		break;
	case shareDenyWrite:
		dwShareMode = FILE_SHARE_READ;
		break;
	case shareDenyRead:
		dwShareMode = FILE_SHARE_WRITE;
		break;
	case shareDenyNone:
		dwShareMode = FILE_SHARE_WRITE | FILE_SHARE_READ;
		break;
	}

	// Note: typeText and typeBinary are used in derived classes only.

	// map modeNoInherit flag
	SECURITY_ATTRIBUTES sa;
	sa.nLength = sizeof(sa);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = (nOpenFlags & modeNoInherit) == 0;

	// map creation flags
	DWORD dwCreateFlag;
	if (nOpenFlags & modeCreate)
	{
		if (nOpenFlags & modeNoTruncate)
			dwCreateFlag = OPEN_ALWAYS;
		else
			dwCreateFlag = CREATE_ALWAYS;
	}
	else
		dwCreateFlag = OPEN_EXISTING;

	// special system-level access flags

	// Random access and sequential scan should be mutually exclusive
	ASSERT((nOpenFlags&(osRandomAccess|osSequentialScan)) != (osRandomAccess|
		osSequentialScan) );

	DWORD dwFlags = FILE_ATTRIBUTE_NORMAL;
	if (nOpenFlags & osNoBuffer)
		dwFlags |= FILE_FLAG_NO_BUFFERING;
	if (nOpenFlags & osWriteThrough)
		dwFlags |= FILE_FLAG_WRITE_THROUGH;
	if (nOpenFlags & osRandomAccess)
		dwFlags |= FILE_FLAG_RANDOM_ACCESS;
	if (nOpenFlags & osSequentialScan)
		dwFlags |= FILE_FLAG_SEQUENTIAL_SCAN;

	// attempt file creation
	HANDLE hFile = ::CreateFile(lpszFileName, dwAccess, dwShareMode, &sa,
		dwCreateFlag, dwFlags, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{		
		return FALSE;
	}

	m_hFile = hFile;
	m_bCloseOnDelete = TRUE;

	return TRUE;
}



UINT CFile::Read(void* lpBuf, UINT nCount)
{	
	ASSERT(m_hFile != INVALID_HANDLE_VALUE);

	if (nCount == 0)
		return 0;   // avoid Win32 "null-read"

	ASSERT(lpBuf != NULL);

	DWORD dwRead = 0;
	::ReadFile(m_hFile, lpBuf, nCount, &dwRead, NULL);		
	return (UINT)dwRead;
}

DWORD CFile::Write(const void* lpBuf, UINT nCount)
{
	ASSERT(m_hFile != INVALID_HANDLE_VALUE);

	if (nCount == 0)
		return 0L;     // avoid Win32 "null-write" option

	ASSERT(lpBuf != NULL);

	DWORD nWritten;
	::WriteFile(m_hFile, lpBuf, nCount, &nWritten, NULL);
	
    return nWritten;
}

ULONGLONG CFile::Seek(LONGLONG lOff, UINT nFrom)
{	
	ASSERT(m_hFile != INVALID_HANDLE_VALUE);
	ASSERT(nFrom == begin || nFrom == end || nFrom == current);
	ASSERT(begin == FILE_BEGIN && end == FILE_END && current == FILE_CURRENT);

   LARGE_INTEGER liOff;

   liOff.QuadPart = lOff;
	liOff.LowPart = ::SetFilePointer(m_hFile, liOff.LowPart, &liOff.HighPart,
	  (DWORD)nFrom);
	if (liOff.LowPart  == (DWORD)-1)
	  if (::GetLastError() != NO_ERROR)
	  {
	//	  CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
	  }

	return liOff.QuadPart;
}

ULONGLONG CFile::GetPosition() const
{	
	ASSERT(m_hFile != INVALID_HANDLE_VALUE);

   LARGE_INTEGER liPos;
   liPos.QuadPart = 0;
	liPos.LowPart = ::SetFilePointer(m_hFile, liPos.LowPart, &liPos.HighPart , FILE_CURRENT);
	if (liPos.LowPart == (DWORD)-1)
	  if (::GetLastError() != NO_ERROR)
	  {
	  }
	  //CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);

	return liPos.QuadPart;
}

void CFile::Flush()
{	
	if (m_hFile == INVALID_HANDLE_VALUE)
		return;

	if (!::FlushFileBuffers(m_hFile))
	{
	
	}
}

void CFile::Close()
{
	ASSERT(m_hFile != INVALID_HANDLE_VALUE);

	BOOL bError = FALSE;
	if (m_hFile != INVALID_HANDLE_VALUE)
		bError = !::CloseHandle(m_hFile);

	m_hFile = INVALID_HANDLE_VALUE;
	m_bCloseOnDelete = FALSE;
	m_strFileName.Empty();

	if (bError)
	{
	
	}
	//	CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
}

void CFile::Abort()
{
	if (m_hFile != INVALID_HANDLE_VALUE)
	{
		// close but ignore errors
		::CloseHandle(m_hFile);
		m_hFile = INVALID_HANDLE_VALUE;
	}
	m_strFileName.Empty();
}

BOOL CFile::LockRange(ULONGLONG dwPos, ULONGLONG dwCount)
{
   ASSERT(m_hFile != INVALID_HANDLE_VALUE);

   ULARGE_INTEGER liPos;
   ULARGE_INTEGER liCount;

   liPos.QuadPart = dwPos;
   liCount.QuadPart = dwCount;
	if (!::LockFile(m_hFile, liPos.LowPart, liPos.HighPart, liCount.LowPart, 
	  liCount.HighPart))
    {
	   return FALSE;
	//	CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
    }
	else
	{
	   return TRUE;
	}

	return TRUE;

}

BOOL CFile::UnlockRange(ULONGLONG dwPos, ULONGLONG dwCount)
{
	ASSERT(m_hFile != INVALID_HANDLE_VALUE);

   ULARGE_INTEGER liPos;
   ULARGE_INTEGER liCount;

   liPos.QuadPart = dwPos;
   liCount.QuadPart = dwCount;
	if (!::UnlockFile(m_hFile, liPos.LowPart, liPos.HighPart, liCount.LowPart,
	  liCount.HighPart))
    {
	   return FALSE;
    }
	else
	{
	   return TRUE;
	}
}

BOOL CFile::SetLength(ULONGLONG dwNewLen)
{
	ASSERT(m_hFile != INVALID_HANDLE_VALUE);

	Seek(dwNewLen, (UINT)begin);

	if (!::SetEndOfFile(m_hFile))
	 {
	   return FALSE;
    }
	else
	{
	   return TRUE;
	}

}

ULONGLONG CFile::GetLength() const
{
   ULARGE_INTEGER liSize;
   liSize.LowPart = ::GetFileSize(m_hFile, &liSize.HighPart);
  
   /*if (liSize.LowPart == (DWORD)-1)
	  if (::GetLastError() != NO_ERROR)
	 {
	   return FALSE;
    }
	else
	{
	   return TRUE;
	}
	*/

	return liSize.QuadPart;
}


BOOL PASCAL CFile::Rename(LPCTSTR lpszOldName, LPCTSTR lpszNewName)
{
	return ::MoveFile((LPTSTR)lpszOldName, (LPTSTR)lpszNewName);
}

BOOL PASCAL CFile::Remove(LPCTSTR lpszFileName)
{
	return ::DeleteFile((LPTSTR)lpszFileName);	
}

